package com.atguigu.service.impl;

import com.atguigu.client.UserFeignClient;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.*;
import com.atguigu.mapper.SeckillProductMapper;
import com.atguigu.result.RetVal;
import com.atguigu.result.RetValCodeEnum;
import com.atguigu.service.SeckillProductService;
import com.atguigu.util.MD5;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 
 * @since 2022-09-18
 */
@Service
public class SeckillProductServiceImpl extends ServiceImpl<SeckillProductMapper, SeckillProduct> implements SeckillProductService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserFeignClient userFeignClient;

    @Override
    public SeckillProduct getSeckillProductFromRedis(Long skuId) {
        return (SeckillProduct) redisTemplate.opsForHash().get(RedisConst.SECKILL_PRODUCT,skuId.toString());
    }

    //处理预下单
    @Override
    public void prepareSeckill(UserSeckillSkuInfo userSeckillSkuInfo) {
        Long skuId = userSeckillSkuInfo.getSkuId();
        String userId = userSeckillSkuInfo.getUserId();
        String seckillState = (String) redisTemplate.opsForValue().get(RedisConst.SECKILL_STATE_PREFIX + skuId);
        //1.再次判断是否卖完 判断秒杀状态
        if (RedisConst.CAN_NOT_SECKILL.equals(seckillState)){
            return ;
        }
        //2.判断此用户是否有预下单
        boolean flag = redisTemplate.opsForValue().setIfAbsent(RedisConst.PREPARE_SECKILL_USERID_SKUID + ":" + userId + ":" + skuId, skuId, RedisConst.PREPARE_SECKILL_LOCK_TIME, TimeUnit.SECONDS);
        if (!flag) {
            return;
        }
        //3.检查是否有库存
        String redisStockSkuId = (String) redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).rightPop();
        if (StringUtils.isEmpty(redisStockSkuId)){
            //通知其他节点修改秒杀状态位
            redisTemplate.convertAndSend(RedisConst.PREPARE_PUB_SUB_SECKILL,skuId+":"+RedisConst.CAN_NOT_SECKILL);
            return;
        }
        //生成临时订单存入redis
        PrepareSeckillOrder prepareSeckillOrder = new PrepareSeckillOrder();
        prepareSeckillOrder.setUserId(userId);
        prepareSeckillOrder.setBuyNum(1);
        SeckillProduct seckillProduct = getSeckillProductFromRedis(skuId);
        prepareSeckillOrder.setSeckillProduct(seckillProduct);
        //生成一个预购订单码
        prepareSeckillOrder.setPrepareOrderCode(MD5.encrypt(userId+skuId));
        redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).put(userId,prepareSeckillOrder);
        //跟新库存量
        updateSeckillStockCount(skuId);
    }

    //5.判断用户是否具备抢购资格
    @Override
    public RetVal hasQualified(Long skuId, String userId) {
        boolean isExist = redisTemplate.hasKey(RedisConst.PREPARE_SECKILL_USERID_SKUID + ":" + userId + ":" + skuId);
        //如果预购单里有用户信息 代表用户有抢购资格
        if (isExist) {
            //拿出用户的预购单
            PrepareSeckillOrder prepareSeckillOrder= (PrepareSeckillOrder) redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).get(userId);
            if (prepareSeckillOrder!=null){
                //返回具备有抢购资格的与预购单信息
                return RetVal.build(prepareSeckillOrder,RetValCodeEnum.PREPARE_SECKILL_SUCCESS);
            }
        }
        //如果用户已经购买过该商品
        Integer orderId = (Integer) redisTemplate.boundHashOps(RedisConst.BOUGHT_SECKILL_USER_ORDER).get(userId);
        if (orderId != null) {
            //代表用户已经抢购成功，页面会显示抢购成功
            return RetVal.build(null,RetValCodeEnum.SECKILL_ORDER_SUCCESS);
        }
        //如果没有预购单 返回继续排队提示
        return RetVal.build(null, RetValCodeEnum.SECKILL_RUN);
    }

    //6.返回秒杀确认页面需要的数据信息
    @Override
    public RetVal seckillConfirm(String userId) {
        //1.获取用户的收货地址
        List<UserAddress> userAddressList = userFeignClient.getUserAddressByUserId(userId);
        //2.获取用户的预购单
        PrepareSeckillOrder prepareSeckillOrder= (PrepareSeckillOrder) redisTemplate.boundHashOps(RedisConst.PREPARE_SECKILL_USERID_ORDER).get(userId);
        if (prepareSeckillOrder == null){
            return RetVal.fail().message("非法请求");
        }
        //3.把预购单的商品信息拿出来
        SeckillProduct seckillProduct = prepareSeckillOrder.getSeckillProduct();
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setSkuId(seckillProduct.getSkuId());
        orderDetail.setSkuName(seckillProduct.getSkuName());
        orderDetail.setImgUrl(seckillProduct.getSkuDefaultImg());
        orderDetail.setSkuNum(prepareSeckillOrder.getBuyNum()+"");
        //订单价格
        orderDetail.setOrderPrice(seckillProduct.getCostPrice());
        List<OrderDetail> orderDetailList = new ArrayList<>();
        orderDetailList.add(orderDetail);

        Map<String, Object> retMap = new HashMap<>();
        retMap.put("userAddressList",userAddressList);
        //这里需要把购物车信息转换到订单详情里面
        retMap.put("orderDetailList",orderDetailList);
        retMap.put("totalMoney",seckillProduct.getCostPrice());
        return RetVal.ok(retMap);
    }

    private void updateSeckillStockCount(Long skuId) {
        //剩余库存量
        Long leftStock = redisTemplate.boundListOps(RedisConst.SECKILL_STOCK_PREFIX + skuId).size();
        SeckillProduct redisSeckillProduct = getSeckillProductFromRedis(skuId);
        //锁定库存量=商品总数量-剩余库存
        Integer totalStock = redisSeckillProduct.getNum();
        Integer lockStock=totalStock-Integer.parseInt(leftStock+"");
        redisSeckillProduct.setStockCount(lockStock);
        //更新到redis中 为了给用户看剩余
        redisTemplate.boundHashOps(RedisConst.SECKILL_PRODUCT).put(skuId.toString(),redisSeckillProduct);
        //更新到数据库 持久化 自定义操作数据库频率
        if (leftStock%2==0) {
            baseMapper.updateById(redisSeckillProduct);
        }
    }
}
